﻿//////////////////////////////////////////////////////////////////////////////
//
//  Copyright © 1998-2024 Glodon Company Limited.  All rights reserved.
//
//  Use of this software is subject to the terms of the Glodon license
//  agreement provided at the time of installation or download, or which
//  otherwise accompanies this software in either electronic or hard copy form.  
//
//////////////////////////////////////////////////////////////////////////////


#pragma once
#include "GnufBase.h"
#include "GnufBaseUtils.h"
#include <QtWidgets/QDialog>

namespace gnuf {

    class WindowTitleBar;
    class ArrangementAreaContent;
    class IQtWindowFramelessStyle;
    class QtWindow;

    class IQtWindowUser
    {
    public:
        virtual void onPostPositionChanged  (const QtWindow *, int x, int y, bool dragging) {}
        virtual void onPostDiscarded        (const QtWindow *) {}
        virtual bool onDoClose              (const QtWindow *) { return true; }
        virtual void onScaleFactorChanged   (const ScaleFactor &) {}
        virtual void onDisplayChanged       () {}
        virtual void onDragingEnded         () {}
        virtual bool onIsMasked             () const { return false; } // unmasked, by default
    };

    class QtWindow : public QDialog
    {
        Q_OBJECT
        Q_PROPERTY(bool ShouldIgnoreRecord READ ShouldIgnoreRecord)
        Q_PROPERTY(bool isMasked READ onIsMasked)
    public:
        enum class ELayout { eUnknown, eVertical };
        QtWindow(
            IQtWindowUser *, 
            bool isSubWindow,
            const QtWindow::ELayout layout = QtWindow::ELayout::eUnknown,
            bool isToolWindow = false,
            bool wantToStayOnTop = false);
        virtual ~QtWindow();

        // Call this method, instead of deleting immediately that 
        // might cause the Qt crash.
        void discard();

        // Returns the user that is using this QtWindow.
        IQtWindowUser * user() const { return m_user; }

        virtual bool ShouldIgnoreRecord() { return true; }

        // Ask if there is nothing at the position.
        bool hasNothingAt(int globalX, int globalY);

        /// \brief Set the mouse left button pressed on the blank.
        /// \param globalX: The global mouse position X.
        /// \param globalY: The global mouse position Y.
        void setMouseLeftButtonPressedOnBlank(int globalX, int globalY);
        /// \brief Set the mouse left button released on the blank.
        void setMouseLeftButtonReleasedOnBlank();

        /// \return Return true during dragging.
        bool isDragging() const { return m_dragging; }

        // Add the customized window title bar. By default, this window
        // is frameless and does not have the window title bar.
        WindowTitleBar * addWindowTitleBar(
            const wchar_t * key,
            const wchar_t * config,
            bool isRelativePath,
            const int fixedHeight);
        WindowTitleBar * windowTitleBar() { return m_windowTitleBar.get(); }

        // Embed/unembed the ArrangementAreaContent.
        void embed(const bool wantToEmbed, ArrangementAreaContent *);

        const ScaleFactor & scaleFactor() const { return m_scaleFactor; }

        void onDpiChanged(unsigned short);
        void onDisplayChanged();

    protected:
        // Inherits from QWidget...
        virtual bool event(QEvent *) override;
        virtual void moveEvent(QMoveEvent *) override;
        virtual bool nativeEvent(const QByteArray &, void *, long *) override;
        virtual void changeEvent(QEvent *) override;
        virtual void keyPressEvent(QKeyEvent*) override;
        virtual void closeEvent(QCloseEvent *) override;
        virtual void timerEvent(QTimerEvent *) override;

        void setUser(IQtWindowUser *);

        virtual bool onIsMasked() {             // for reading the Q_PROPERTY (isMasked)
            return (nullptr == m_user ? false : // unmasked, if no user
                m_user->onIsMasked());          // use the decision that the user makes
        }

    signals:
        void onClosed();

    private:
        void setScaleFactor(const ScaleFactor &);
        void setDragging(bool, QMoveEvent * qtEvt = nullptr);
        void stayOnTop();

        IQtWindowUser * m_user = nullptr;
        gcmp::OwnerPtr<WindowTitleBar> m_windowTitleBar;
        gcmp::OwnerPtr<IQtWindowFramelessStyle> m_framelessStyle;
        ScaleFactor m_scaleFactor;
        struct { bool valid = false; QPoint pos; } m_mouseLeftButtonPressedOnBlank;
        bool m_dragging = false;
        int m_timerIdToStayOnTop = -1;
    };

}
